﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SharpSxwnl;
using System.Runtime.InteropServices;
using System.Diagnostics.Contracts;
using System.Runtime.Versioning;
using System.Drawing.Imaging;
using System.IO;
using Syncfusion.Pdf;
using Syncfusion.Pdf.Graphics;
using System.Diagnostics;
using Syncfusion.Licensing;

namespace 天机万年历.自定义控件
{
    public partial class LunarControl : UserControl
    {
        [Category("日历"), Description("自动刷新"), DefaultValue(true)]
        public bool AutoReLoad { get; set; } = true;

        private DayOfWeek weekStart = DayOfWeek.Sunday;
        [Category("日历"), Description("星期开始"), DefaultValue(DayOfWeek.Sunday)]
        public DayOfWeek WeekStart
        {
            get => weekStart;
            set
            {
                if (weekStart != value)
                {
                    weekStart = value;
                    if (AutoReLoad) ReLoad();
                }
            }
        }

        private int year = 2019;
        [Category("日历"), Description("哪一年"), DefaultValue(2019)]
        public int Year
        {
            get { return year; }
            set
            {
                if (year != value)
                {
                    year = value;
                    if (AutoReLoad) ReLoad();
                }
            }
        }
        private int month = 1;
        [Category("日历"), Description("哪一月"), DefaultValue(1)]
        public int Month
        {
            get => month; set
            {
                if (month != value)
                {
                    month = value;
                    if (AutoReLoad) ReLoad();
                }
            }
        }
        [Category("日历"), Description("显示农历节日"), DefaultValue(true)]
        public bool 显示农历节日 { get; set; } = true;

        [Category("日历"), Description("农历节日颜色"), DefaultValue(typeof(Color), "LawnGreen")]
        public Color 农历节日颜色 { get; set; } = Color.LawnGreen;

        [Category("日历"), Description("显示公历节日"), DefaultValue(true)]
        public bool 显示公历节日 { get; set; } = true;

        [Category("日历"), Description("公历节日颜色"), DefaultValue(typeof(Color), "LawnGreen")]
        public Color 公历节日颜色 { get; set; } = Color.LawnGreen;

        public enum 星期中文列表
        {
            星期日 = 0,
            星期一,
            星期二,
            星期三,
            星期四,
            星期五,
            星期六
        }
        public LunarControl()
        {
            InitializeComponent();
        }
        public const int TitleHeight = 24;
        List<LunarLabel> WeekList = new List<LunarLabel>();
        List<LunarDay> DayList = new List<LunarDay>();
        private void LunarControl_Load(object sender, EventArgs e)
        {
            panel1.Left = 0;
            panel1.Top = 0;
            var ld = new LunarDay();
            panel1.Width = ld.Width * 7;
            panel1.Height = ld.Height * 6 + TitleHeight;
            for (int i = 0; i < 7; i++)
            {
                WeekList.Add(new LunarLabel()
                {
                    Width = ld.Width,
                    Height = TitleHeight,
                    AutoSize = false,
                    Left = ld.Width * i,
                    Top = 0,
                    Text = "星期一",
                    TextAlign = ContentAlignment.MiddleCenter,
                    Font = new Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)))
                    //BackColor = Color.Transparent
                });
                panel1.Controls.Add(WeekList.Last());

            }
            this.Width = panel1.Width;
            this.Height = panel1.Height;
            ld.Left = 0;
            ld.Top = TitleHeight;
            ld.Click += LunarDay_Click;
            DayList.Add(ld);
            panel1.Controls.Add(DayList.Last());
            for (int y = 0; y < 6; y++)
            {
                for (int x = 0; x < 7; x++)
                {
                    if (x == 0 && y == 0) continue;
                    DayList.Add(new LunarDay() { Left = ld.Width * x, Top = ld.Height * y + TitleHeight });
                    DayList.Last().Click += LunarDay_Click;
                    panel1.Controls.Add(DayList.Last());
                }
            }

            ReLoad();
        }

        Dictionary<int, int> WeekXChange = new Dictionary<int, int>() { { 0, 7 }, { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 } };
        private Lunar lunar = new Lunar();
        public void ReLoad()
        {
            if (WeekList.Count == 0)
                return;
            DayOfWeek week = WeekStart;
            for (int i = 0; i < 7; i++)
            {
                var lb = WeekList[i];
                lb.Text = ((星期中文列表)week).ToString();
                week += 1;
                if ((int)week >= 7)
                {
                    week = DayOfWeek.Sunday;
                }
            }
            DateTime Day = new DateTime(Year, Month, 1);
            var weekc = Day.DayOfWeek;
            int ws = 0;
            if (weekc >= WeekStart)
                ws = weekc - WeekStart;
            else
                ws = weekc - WeekStart + 7;
            int j = 0;
            if (ws > 0)
            {
                j = 0;
                for (int i = ws; i > 0; i--)
                {
                    DateTime d = Day.AddDays(-i);
                    var ln = DayList[j++];
                    ln.Date = d;
                    ln.显示农历节日 = 显示农历节日;
                    ln.显示公历节日 = 显示公历节日;
                    ln.农历节日颜色 = 农历节日颜色;
                    ln.公历节日颜色 = 公历节日颜色;
                    ln.DayInMonth = false;
                }
            }
            for (int i = 0; i < DateTime.DaysInMonth(Year, Month); i++)
            {
                var ln = DayList[ws];
                ln.Date = Day;
                ln.显示农历节日 = 显示农历节日;
                ln.显示公历节日 = 显示公历节日;
                ln.农历节日颜色 = 农历节日颜色;
                ln.公历节日颜色 = 公历节日颜色;
                ln.Visible = true;
                ln.DayInMonth = true;
                Day = Day.AddDays(1);
                ws++;
            }
            int wss = 0;
            if (ws <= 35)
            {
                panel1.Height = DayList[0].Height * 5 + TitleHeight;
                wss = 35 - ws;
            }
            else
            {
                panel1.Height = DayList[0].Height * 6 + TitleHeight;
                wss = 42 - ws;
            }
            j = 0;
            if (wss > 0)
            {
                int wsss = wss;
                for (int i = 0; i < wsss; i++)
                {
                    DateTime d = Day.AddDays(i);
                    var ln = DayList[ws + (j++)];
                    ln.Date = d;
                    ln.显示农历节日 = 显示农历节日;
                    ln.显示公历节日 = 显示公历节日;
                    ln.农历节日颜色 = 农历节日颜色;
                    ln.公历节日颜色 = 公历节日颜色;
                    ln.Visible = true;
                    ln.DayInMonth = false;
                }
            }
            wss = 42 - (ws + wss);
            if (wss > 0)
            {
                int wsss = wss;
                for (int i = 0; i < wsss; i++)
                {
                    DateTime d = Day.AddDays(i);
                    var ln = DayList[ws + (j++)];
                    ln.Visible = false;
                }
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            ReLoad();
            base.OnPaint(e);
        }
        private void LunarDay_Click(object sender, EventArgs e)
        {
            LunarDay lunarDay = sender as LunarDay;

            Contract.Requires(e != null);

            ((LunarHandler)Events[EventClick])?.Invoke(this, new LunarEventArgs() { Date = lunarDay.Date });
        }

        [ComVisible(true)]
        public delegate void LunarHandler(object sender, LunarEventArgs e);

        public class LunarEventArgs : EventArgs
        {
            public DateTime Date;
        }
        private static readonly object EventClick = new object();
        new public event LunarHandler Click
        {
            add
            {
                Events.AddHandler(EventClick, value);
            }
            remove
            {
                Events.RemoveHandler(EventClick, value);
            }
        }

        const int WM_PRINT = 0x0317;

        const int PRF_CHECKVISIBLE = 0x00000001,
        PRF_NONCLIENT = 0x00000002,
        PRF_CLIENT = 0x00000004,
        PRF_ERASEBKGND = 0x00000008,
        PRF_CHILDREN = 0x00000010;

        [DllImport("gdi32.dll", SetLastError = true, ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        private static extern bool BitBlt(HandleRef hDC, int x, int y, int nWidth, int nHeight,
                                         HandleRef hSrcDC, int xSrc, int ySrc, int dwRop);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        [ResourceExposure(ResourceScope.None)]
        public static extern IntPtr SendMessage(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern bool OpenClipboard(IntPtr hWndNewOwner);
        [DllImport("user32.dll")]
        static extern bool EmptyClipboard();
        [DllImport("user32.dll")]
        static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
        [DllImport("user32.dll")]
        static extern bool CloseClipboard();
        [DllImport("gdi32.dll")]
        static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, IntPtr hNULL);
        [DllImport("gdi32.dll")]
        static extern bool DeleteEnhMetaFile(IntPtr hemf);
        [DllImport("gdi32")]
        public static extern int GetEnhMetaFileBits(IntPtr hemf, int cbBuffer, byte[] lpbBuffer);

        private void Panel1_Resize(object sender, EventArgs e)
        {
            this.Size = panel1.Size;
        }

        public void SaveToEMF(string filename)
        {
            File.WriteAllBytes(filename, SaveToEMFBytes());
        }
        public void SaveToPDF(string filename)
        {
            PdfDocument doc = new PdfDocument();
            PdfMetafile metaChart = new PdfMetafile(new MemoryStream(SaveToEMFBytes()));
            doc.PageSettings.Orientation = PdfPageOrientation.Landscape;
            doc.PageSettings.Size = new SizeF(metaChart.Width, metaChart.Height);
            PdfPage page = doc.Pages.Add();
            PdfGraphics graphics = page.Graphics;
            PdfMetafileLayoutFormat format = new PdfMetafileLayoutFormat();
            format.SplitImages = true;
            format.SplitTextLines = true;
            metaChart.Draw(page, PointF.Empty, format);
            doc.Save(filename);
            doc.Close(true);
        }
        public byte[] SaveToEMFBytes()
        {
            Graphics g1 = this.CreateGraphics();
            IntPtr hdc = g1.GetHdc();
            Metafile mf = new Metafile(hdc, new Rectangle(0, 0, panel1.Width, panel1.Height), MetafileFrameUnit.Pixel, EmfType.EmfPlusOnly);
            g1.ReleaseHdc(hdc);
            g1.Dispose();

            Graphics g2 = Graphics.FromImage(mf);
            Draw(g2);
            g2.Dispose();

            var enhMetafileHandle = mf.GetHenhmetafile();
            int bufferSize = GetEnhMetaFileBits(enhMetafileHandle, 0, null); // Get required buffer size.
            byte[] buffer = new byte[bufferSize]; // Allocate sufficient buffer
            if (GetEnhMetaFileBits(enhMetafileHandle, bufferSize, buffer) <= 0) // Get raw metafile data.
                throw new SystemException("DoTheTrick.GetEnhMetaFileBits");

            MemoryStream ms = new MemoryStream();
            ms.Write(buffer, 0, bufferSize);
            ms.Close();
            DeleteEnhMetaFile(enhMetafileHandle);
            return buffer;
        }

        public void Draw(Graphics g)
        {
            foreach (var l in WeekList)
            {
                l.CustomPaint(g);
            }
            foreach (var l in DayList)
            {
                l.Draw(g);
            }
        }
    }
}
